<template>

  <div id="upload-main">
    <div style="width: 1400px;position: relative;margin-top: 32px;
    background-color: white;padding: 32px 64px 16px 16px;border-radius: 4px;">

      <el-form :model="videoInfo" label-width="120px">

        <el-form-item label="视频标题">
          <el-input v-model="videoInfo.title" />
        </el-form-item>

        <el-form-item label="视频简介">
          <el-input v-model="videoInfo.desc" />
        </el-form-item>

        <el-form-item label="视频封面">

          <el-upload :show-file-list="false" :on-change="selectImg">
            <div class="uploader-div">
              <img class="uploader-img-pre" v-if="videoHeadImgUrl" :src="videoHeadImgUrl" />
              <el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon>
            </div>
          </el-upload>

        </el-form-item>

        <el-form-item label="上传视频">

          <el-upload :show-file-list="false" :on-change="selectFile">
            <div class="uploader-div">
              <video class="uploader-video-pre" v-if="videoFile" :src="videoFileUrl" />
              <el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon>
            </div>
          </el-upload>

        </el-form-item>

        <el-form-item>
          <el-button type="primary" @click="uploadVideo">{{ button_text }}</el-button>
        </el-form-item>

      </el-form>

    </div>
  </div>

</template>

<script setup>
import {onMounted, ref} from "vue";
import {showElMessage} from "../../util/common";
import axios from "axios";
import {postRequest} from "../../util/requestUtil";
import {VIDEO_CHUNK_UPLOAD_API, VIDEO_INFO_UPLOAD_API, VIDEO_UPLOAD_UUID_API} from "../../api/video";
import {ElLoading} from "element-plus";
import {useRouter} from "vue-router";

const router = useRouter();

const videoInfo = ref({title: '', desc: ''});

const videoHeadImg = ref('');
const videoHeadImgUrl = ref('');
const videoFileUrl = ref('');
const videoFile = ref('');

const button_text = ref('上传')

function selectImg(file){
  videoHeadImg.value = file;
  videoHeadImgUrl.value = URL.createObjectURL(file.raw);
}

function selectFile(file) {
  chunkIndex = 0;
  videoFile.value = file;
  videoFileUrl.value = URL.createObjectURL(file.raw);
}

function canUpload(){
  return videoHeadImg.value && videoFile.value && videoInfo.value.title && videoInfo.value.desc;
}

const videoUUID = ref(void 0);

function getVideoUUID(){
  if (videoUUID.value){
    return videoUUID.value;
  }
  postRequest(VIDEO_UPLOAD_UUID_API, {}, (data)=>{
    videoUUID.value = data.data;
  }, ()=>{}, ()=>{}, false)
}

const chunkSize = 1024 * 1024; // 1MB

const headers = {
  'Content-Type': 'multipart/form-data',
};

const maxReTry = 5;
let reTryCount = 0;
let chunkIndex = 0;
function canPostReTry(){
  reTryCount++;
  if (reTryCount >= maxReTry){
    reTryCount = 0;
    return false;
  }
  return true;
}

async function uploadChunks(chunks, file, loading){
  for (let i = chunkIndex; i < chunks; i++) {
    const start = i * chunkSize;
    const end = Math.min(start + chunkSize, file.size);
    const chunk = file.slice(start, end);

    const formData = new FormData();
    formData.append('uuid', getVideoUUID());
    formData.append('chunkIndex', i);
    formData.append('totalChunks', chunks);
    formData.append('chunk', chunk, 'chunk');

    let response;
    try {
      response = await axios.post(VIDEO_CHUNK_UPLOAD_API, formData, {headers: headers});
      let nums = (i*100/chunks);
      console.log(nums)
      loading.setText(nums.toFixed(2)+"%")
    }catch (e){
      if (canPostReTry()) {
        i--;
        continue;
      }else {
        showElMessage(false, "上传失败", "error")
        chunkIndex = i;
        button_text.value = "继续上传"
        return false;
      }
    }
    let state = response.data.state;
    if (state!==1){
      // 直接合并
      if (state===2){
        return true;
      }
      if (state===-4){
        showElMessage(false, response.data.message, "warning")
        return false;
      }
      if (canPostReTry()) {
        i--;
        continue;
      }else {
        showElMessage(false, "上传失败", "error")
        chunkIndex = i;
        button_text.value = "继续上传"
        return false;
      }
    }

    if (i===chunks-1){
      return true;
    }
  }

  return false;
}

async function mergeVideo(formData, chunks){
  // 通知服务器合并切片
  let response;
  try{
    response = await axios.post(VIDEO_INFO_UPLOAD_API, formData)
  }catch (e){
    showElMessage(false, e, "error")
    return false;
  }

  const state = response.data.state;
  if (state===1){
    showElMessage(false, "视频上传成功", "success")
    return true;
  }
  else if (state===-4){
    showElMessage(false, "视频已上传", "error")
  }
  else if (state===-3){
    showElMessage(false, "uuid不匹配", "error")
    await postRequest(VIDEO_UPLOAD_UUID_API, {}, (data)=>{
      videoUUID.value = data.data;
    }, ()=>{}, ()=>{}, false)
  }
  else if (state===-2){
    showElMessage(false, "区块数量异常", "error")
    chunkIndex = response.data.index;
    if (chunkIndex > chunks){
      chunkIndex = 0;
    }
  }
  else if (state===-1){
    showElMessage(false, "区块数量异常", "error")
    chunkIndex = response.data.index;
  }
  button_text.value = "继续上传"
  return false;
}

async function uploadVideo(){
  if (!canUpload()){
    showElMessage(false, "视频信息不完整！", "warning");
    return
  }

  let file = videoFile.value.raw;

  const chunks = Math.ceil(file.size / chunkSize);

  const loading = ElLoading.service({
    lock: true,
    text: 'Loading',
    background: 'rgba(0, 0, 0, 0.7)',
  });

  let canMerge = await uploadChunks(chunks, file, loading);

  if (!canMerge){
    loading.close();
    return
  }

  chunkIndex = chunks - 1;

  const formData = new FormData();
  formData.append('uuid', getVideoUUID());
  formData.append('totalChunks', chunks);
  formData.append('title', videoInfo.value.title);
  formData.append('desc', videoInfo.value.desc);
  formData.append('img', videoHeadImg.value.raw, 'img');

  const mergeOk = await mergeVideo(formData, chunks);
  if (mergeOk){
    loading.setText("100%");
    setTimeout(()=>{
      window.location.reload()
    }, 300);
  }
  loading.close();
}

onMounted(()=>{
  postRequest(VIDEO_UPLOAD_UUID_API, {}, (data)=>{
    videoUUID.value = data.data;
  }, ()=>{}, ()=>{}, false)
})
</script>

<style scoped>

#upload-main{
  display: flex;
  justify-content: center;
}

.uploader-div:hover{
  border-color: var(--el-color-primary)!important;
}

.uploader-div{
  display: flex;
  width: 176px;
  height: 176px;
  border: #6b757b 1px dashed;
  justify-content: center;
  align-items: center;
}

.uploader-img-pre{
  width: 176px;
  height: 176px;
  object-fit: cover;
}

.uploader-video-pre{
  width: 176px;
  height: 176px;
  object-fit: cover;
}

</style>